[crossover~] 24dB/oct crossover filter
Splits an input signal into two output signals at the crossover frequency
Default frequency is 1000 Hertz
Inlet 1: signal
Outlet 1: low signal
Outlet 2: high signal
Float: crossover frequency
Argument: crossover frequency
|
Download
crossover~.zip - object, help patch, source code
Source Code
//------------------------------------------------------------------------------
// Audio Crossover Object for Pd
//
// crossover~.c
//
// Cuts an input signal into two output signals at the crossover frequency
//
// Created by Cooper Baker on 10/29/14.
// Copyright (c) 2014 Cooper Baker. All rights reserved.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// headers
//------------------------------------------------------------------------------
// main header for pd
#include "m_pd.h"
// utility header for Pd Spectral Toolkit project
#include "utility.h"
// math header for fancy math
#include <math.h>
// stdio for debugging
#include <stdio.h>
// disable compiler warnings on windows
#ifdef NT
#pragma warning( disable : 4244 )
#pragma warning( disable : 4305 )
#endif
//------------------------------------------------------------------------------
// definitions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// crossover_class - pointer to this object's definition
//------------------------------------------------------------------------------
static t_class* crossover_class;
static t_class* crossover_arg_class;
//------------------------------------------------------------------------------
// crossover - data structure holding this object's data
//------------------------------------------------------------------------------
typedef struct crossover
{
// this object - must always be first variable in struct
t_object object;
// needed for CLASS_MAINSIGNALIN macro call in crossover_tilde_setup
t_float inlet_1;
// coefficients for low pass filters
double lb0, lb1, lb2, la1, la2;
// coefficients for high pass filters
double hb0, hb1, hb2, ha1, ha2;
// sample memory for low pass filters
double l1x1, l1x2, l1y1, l1y2;
double l2x1, l2x2, l2y1, l2y2;
// sample memory for high pass filters
double h1x1, h1x2, h1y1, h1y2;
double h2x1, h2x2, h2y1, h2y2;
// cutoff frequency for both filters
t_float freq;
// sample rate
t_float sr;
// filter quality
t_float q;
} t_crossover;
//------------------------------------------------------------------------------
// function prototypes
//------------------------------------------------------------------------------
static void crossover_float ( t_crossover* object, t_floatarg number );
static void crossover_calc_coeffs ( t_crossover* object );
static t_int* crossover_perform ( t_int* io );
static void crossover_dsp ( t_crossover* object, t_signal **sig );
static void* crossover_new ( t_symbol* selector, t_int items, t_atom* list );
void crossover_tilde_setup ( void );
//------------------------------------------------------------------------------
// crossover_calc_coeffs - calculates filter coefficients
//
// Adapted From:
// Cookbook formulae for audio EQ biquad filter coefficients
// By Robert Bristow-Johnson
// http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
//
//------------------------------------------------------------------------------
static void crossover_calc_coeffs( t_crossover* object )
{
double w0 = C_2_PI * object->freq / object->sr;
double cos_w0 = cos( w0 );
double alpha = sin( w0 ) / ( 2.0 * object->q );
double a0 = 1 + alpha;
// Lowpass
//-------------------------------------------
object->lb0 = ( ( 1 - cos_w0 ) * 0.5 ) / a0;
object->lb1 = ( 1 - cos_w0 ) / a0;
object->lb2 = ( ( 1 - cos_w0 ) * 0.5 ) / a0;
object->la1 = ( -2 * cos_w0 ) / a0;
object->la2 = ( 1 - alpha ) / a0;
// Highpass
//-------------------------------------------
object->hb0 = ( ( 1 + cos_w0 ) * 0.5 ) / a0;
object->hb1 = -( 1 + cos_w0 ) / a0;
object->hb2 = ( ( 1 + cos_w0 ) * 0.5 ) / a0;
object->ha1 = ( -2 * cos_w0 ) / a0;
object->ha2 = ( 1 - alpha ) / a0;
}
//------------------------------------------------------------------------------
// crossover_perform - the signal processing function of this object
//------------------------------------------------------------------------------
static t_int* crossover_perform( t_int* io )
{
// store variables from dsp input/output array
t_float* in = ( t_float* )( io[ 1 ] );
t_float* out1 = ( t_float* )( io[ 2 ] );
t_float* out2 = ( t_float* )( io[ 3 ] );
t_int frames = ( t_int )( io[ 4 ] );
t_crossover* o = ( t_crossover* )( io[ 5 ] );
// signal vector iterator variable
t_int n = -1;
// input sample
double x_in = 0;
// middle samples
double x_lm;
double x_hm;
// output samples
double y_lp;
double y_hp;
// filter the input samples for each band
while( ++n < frames )
{
// store input sample
x_in = in[ n ];
// Lowpass
//------------------------------------------------------------------
// stage one
x_lm = o->lb0 * x_in + o->lb1 * o->l1x1 + o->lb2 * o->l1x2 - o->la1 * o->l1y1 - o->la2 * o->l1y2;
o->l1x2 = o->l1x1;
o->l1x1 = x_in;
o->l1y2 = o->l1y1;
o->l1y1 = x_lm;
// stage two
y_lp = o->lb0 * x_lm + o->lb1 * o->l2x1 + o->lb2 * o->l2x2 - o->la1 * o->l2y1 - o->la2 * o->l2y2;
o->l2x2 = o->l2x1;
o->l2x1 = x_lm;
o->l2y2 = o->l2y1;
o->l2y1 = y_lp;
// store output
out1[ n ] = y_lp;
// Highpass
//------------------------------------------------------------------
// stage one
x_hm = o->hb0 * x_in + o->hb1 * o->h1x1 + o->hb2 * o->h1x2 - o->ha1 * o->h1y1 - o->ha2 * o->h1y2;
o->h1x2 = o->h1x1;
o->h1x1 = x_in;
o->h1y2 = o->h1y1;
o->h1y1 = x_hm;
// stage two
y_hp = o->hb0 * x_hm + o->hb1 * o->h2x1 + o->hb2 * o->h2x2 - o->ha1 * o->h2y1 - o->ha2 * o->h2y2;
o->h2x2 = o->h2x1;
o->h2x1 = x_hm;
o->h2y2 = o->h2y1;
o->h2y1 = y_hp;
// store output
out2[ n ] = y_hp;
}
// return the dsp input/output array address plus one more than its size
// to provide a pointer to the next perform function in pd's call list
return &( io[ 6 ] );
}
//------------------------------------------------------------------------------
// crossover_dsp - installs this object's dsp function in pd's callback list
//------------------------------------------------------------------------------
static void crossover_dsp( t_crossover* object, t_signal **sig )
{
// store sample rate
object->sr = sig[ 0 ]->s_sr;
// calculate coefficients
crossover_calc_coeffs( object );
// dsp_add arguments
//--------------------------------------------------------------------------
// perform routine
// number of passed parameters
// inlet sample vector
// outlet 1 sample vector
// outlet 2 sample vector
// sample frames to process (vector size)
// object pointer
dsp_add( crossover_perform, 5, sig[ 0 ]->s_vec, sig[ 1 ]->s_vec, sig[ 2 ]->s_vec, sig[ 0 ]->s_n, object );
}
//------------------------------------------------------------------------------
// crossover_float - handles float input
//------------------------------------------------------------------------------
static void crossover_float( t_crossover* object, t_floatarg number )
{
object->freq = number;
crossover_calc_coeffs( object );
}
//------------------------------------------------------------------------------
// crossover_new - instantiates a copy of this object in pd
//------------------------------------------------------------------------------
static void* crossover_new( t_symbol* selector, t_int items, t_atom* list )
{
// create a pointer to this object
t_crossover* object = ( t_crossover* )pd_new( crossover_class );
// create new signal outlets for this object
outlet_new( &object->object, gensym( "signal" ) );
outlet_new( &object->object, gensym( "signal" ) );
// set quality of filters
object->q = DbToA( -3.0 );
// set initial sampling rate in case crossover_calc_coeffs is called
object->sr = 44100;
// parse object arguments
if( items > 1 )
{
pd_error( object, "crossover~: extra arguments ignored" );
}
if( items )
{
if( list[ 0 ].a_type == A_FLOAT )
{
object->freq = atom_getfloatarg( 0, ( int )items, list );
}
else
{
pd_error( object, "crossover~: invalid argument type" );
}
}
else
{
object->freq = 1000;
}
return object;
}
//------------------------------------------------------------------------------
// crossover_tilde_setup - describes the attributes of this object to pd so it may be properly instantiated
// (must always be named with _tilde replacing ~ in the object name)
//------------------------------------------------------------------------------
void crossover_tilde_setup( void )
{
// crossover class
//--------------------------------------------------------------------------
// creates an instance of this object and describes it to pd
crossover_class = class_new( gensym( "crossover~" ), ( t_newmethod )crossover_new, 0, sizeof( t_crossover ), 0, A_GIMME, 0 );
// declares leftmost inlet as a signal inlet
CLASS_MAINSIGNALIN( crossover_class, t_crossover, inlet_1 );
// installs crossover_dsp so that it will be called when dsp is turned on
class_addmethod( crossover_class, ( t_method )crossover_dsp, gensym( "dsp" ), 0 );
// add float handler
class_addfloat( crossover_class, crossover_float );
/*
// crossover arg class
//--------------------------------------------------------------------------
// creates an instance of this object and describes it to pd
crossover_arg_class = class_new( gensym( "crossover~" ), 0, 0, sizeof( t_crossover ), 0, 0 );
// declares leftmost inlet as a signal inlet
CLASS_MAINSIGNALIN( crossover_class, t_crossover, inlet_1 );
// installs crossover_dsp so that it will be called when dsp is turned on
class_addmethod( crossover_arg_class, ( t_method )crossover_dsp, gensym( "dsp" ), 0 );
*/
// announce this object in the pd console
Announce( "crossover~: splits signal at crossover frequency - v1.0" );
}
//------------------------------------------------------------------------------
// EOF
//------------------------------------------------------------------------------
// Audio Crossover Object for Pd
//
// crossover~.c
//
// Cuts an input signal into two output signals at the crossover frequency
//
// Created by Cooper Baker on 10/29/14.
// Copyright (c) 2014 Cooper Baker. All rights reserved.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// headers
//------------------------------------------------------------------------------
// main header for pd
#include "m_pd.h"
// utility header for Pd Spectral Toolkit project
#include "utility.h"
// math header for fancy math
#include <math.h>
// stdio for debugging
#include <stdio.h>
// disable compiler warnings on windows
#ifdef NT
#pragma warning( disable : 4244 )
#pragma warning( disable : 4305 )
#endif
//------------------------------------------------------------------------------
// definitions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// crossover_class - pointer to this object's definition
//------------------------------------------------------------------------------
static t_class* crossover_class;
static t_class* crossover_arg_class;
//------------------------------------------------------------------------------
// crossover - data structure holding this object's data
//------------------------------------------------------------------------------
typedef struct crossover
{
// this object - must always be first variable in struct
t_object object;
// needed for CLASS_MAINSIGNALIN macro call in crossover_tilde_setup
t_float inlet_1;
// coefficients for low pass filters
double lb0, lb1, lb2, la1, la2;
// coefficients for high pass filters
double hb0, hb1, hb2, ha1, ha2;
// sample memory for low pass filters
double l1x1, l1x2, l1y1, l1y2;
double l2x1, l2x2, l2y1, l2y2;
// sample memory for high pass filters
double h1x1, h1x2, h1y1, h1y2;
double h2x1, h2x2, h2y1, h2y2;
// cutoff frequency for both filters
t_float freq;
// sample rate
t_float sr;
// filter quality
t_float q;
} t_crossover;
//------------------------------------------------------------------------------
// function prototypes
//------------------------------------------------------------------------------
static void crossover_float ( t_crossover* object, t_floatarg number );
static void crossover_calc_coeffs ( t_crossover* object );
static t_int* crossover_perform ( t_int* io );
static void crossover_dsp ( t_crossover* object, t_signal **sig );
static void* crossover_new ( t_symbol* selector, t_int items, t_atom* list );
void crossover_tilde_setup ( void );
//------------------------------------------------------------------------------
// crossover_calc_coeffs - calculates filter coefficients
//
// Adapted From:
// Cookbook formulae for audio EQ biquad filter coefficients
// By Robert Bristow-Johnson
// http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
//
//------------------------------------------------------------------------------
static void crossover_calc_coeffs( t_crossover* object )
{
double w0 = C_2_PI * object->freq / object->sr;
double cos_w0 = cos( w0 );
double alpha = sin( w0 ) / ( 2.0 * object->q );
double a0 = 1 + alpha;
// Lowpass
//-------------------------------------------
object->lb0 = ( ( 1 - cos_w0 ) * 0.5 ) / a0;
object->lb1 = ( 1 - cos_w0 ) / a0;
object->lb2 = ( ( 1 - cos_w0 ) * 0.5 ) / a0;
object->la1 = ( -2 * cos_w0 ) / a0;
object->la2 = ( 1 - alpha ) / a0;
// Highpass
//-------------------------------------------
object->hb0 = ( ( 1 + cos_w0 ) * 0.5 ) / a0;
object->hb1 = -( 1 + cos_w0 ) / a0;
object->hb2 = ( ( 1 + cos_w0 ) * 0.5 ) / a0;
object->ha1 = ( -2 * cos_w0 ) / a0;
object->ha2 = ( 1 - alpha ) / a0;
}
//------------------------------------------------------------------------------
// crossover_perform - the signal processing function of this object
//------------------------------------------------------------------------------
static t_int* crossover_perform( t_int* io )
{
// store variables from dsp input/output array
t_float* in = ( t_float* )( io[ 1 ] );
t_float* out1 = ( t_float* )( io[ 2 ] );
t_float* out2 = ( t_float* )( io[ 3 ] );
t_int frames = ( t_int )( io[ 4 ] );
t_crossover* o = ( t_crossover* )( io[ 5 ] );
// signal vector iterator variable
t_int n = -1;
// input sample
double x_in = 0;
// middle samples
double x_lm;
double x_hm;
// output samples
double y_lp;
double y_hp;
// filter the input samples for each band
while( ++n < frames )
{
// store input sample
x_in = in[ n ];
// Lowpass
//------------------------------------------------------------------
// stage one
x_lm = o->lb0 * x_in + o->lb1 * o->l1x1 + o->lb2 * o->l1x2 - o->la1 * o->l1y1 - o->la2 * o->l1y2;
o->l1x2 = o->l1x1;
o->l1x1 = x_in;
o->l1y2 = o->l1y1;
o->l1y1 = x_lm;
// stage two
y_lp = o->lb0 * x_lm + o->lb1 * o->l2x1 + o->lb2 * o->l2x2 - o->la1 * o->l2y1 - o->la2 * o->l2y2;
o->l2x2 = o->l2x1;
o->l2x1 = x_lm;
o->l2y2 = o->l2y1;
o->l2y1 = y_lp;
// store output
out1[ n ] = y_lp;
// Highpass
//------------------------------------------------------------------
// stage one
x_hm = o->hb0 * x_in + o->hb1 * o->h1x1 + o->hb2 * o->h1x2 - o->ha1 * o->h1y1 - o->ha2 * o->h1y2;
o->h1x2 = o->h1x1;
o->h1x1 = x_in;
o->h1y2 = o->h1y1;
o->h1y1 = x_hm;
// stage two
y_hp = o->hb0 * x_hm + o->hb1 * o->h2x1 + o->hb2 * o->h2x2 - o->ha1 * o->h2y1 - o->ha2 * o->h2y2;
o->h2x2 = o->h2x1;
o->h2x1 = x_hm;
o->h2y2 = o->h2y1;
o->h2y1 = y_hp;
// store output
out2[ n ] = y_hp;
}
// return the dsp input/output array address plus one more than its size
// to provide a pointer to the next perform function in pd's call list
return &( io[ 6 ] );
}
//------------------------------------------------------------------------------
// crossover_dsp - installs this object's dsp function in pd's callback list
//------------------------------------------------------------------------------
static void crossover_dsp( t_crossover* object, t_signal **sig )
{
// store sample rate
object->sr = sig[ 0 ]->s_sr;
// calculate coefficients
crossover_calc_coeffs( object );
// dsp_add arguments
//--------------------------------------------------------------------------
// perform routine
// number of passed parameters
// inlet sample vector
// outlet 1 sample vector
// outlet 2 sample vector
// sample frames to process (vector size)
// object pointer
dsp_add( crossover_perform, 5, sig[ 0 ]->s_vec, sig[ 1 ]->s_vec, sig[ 2 ]->s_vec, sig[ 0 ]->s_n, object );
}
//------------------------------------------------------------------------------
// crossover_float - handles float input
//------------------------------------------------------------------------------
static void crossover_float( t_crossover* object, t_floatarg number )
{
object->freq = number;
crossover_calc_coeffs( object );
}
//------------------------------------------------------------------------------
// crossover_new - instantiates a copy of this object in pd
//------------------------------------------------------------------------------
static void* crossover_new( t_symbol* selector, t_int items, t_atom* list )
{
// create a pointer to this object
t_crossover* object = ( t_crossover* )pd_new( crossover_class );
// create new signal outlets for this object
outlet_new( &object->object, gensym( "signal" ) );
outlet_new( &object->object, gensym( "signal" ) );
// set quality of filters
object->q = DbToA( -3.0 );
// set initial sampling rate in case crossover_calc_coeffs is called
object->sr = 44100;
// parse object arguments
if( items > 1 )
{
pd_error( object, "crossover~: extra arguments ignored" );
}
if( items )
{
if( list[ 0 ].a_type == A_FLOAT )
{
object->freq = atom_getfloatarg( 0, ( int )items, list );
}
else
{
pd_error( object, "crossover~: invalid argument type" );
}
}
else
{
object->freq = 1000;
}
return object;
}
//------------------------------------------------------------------------------
// crossover_tilde_setup - describes the attributes of this object to pd so it may be properly instantiated
// (must always be named with _tilde replacing ~ in the object name)
//------------------------------------------------------------------------------
void crossover_tilde_setup( void )
{
// crossover class
//--------------------------------------------------------------------------
// creates an instance of this object and describes it to pd
crossover_class = class_new( gensym( "crossover~" ), ( t_newmethod )crossover_new, 0, sizeof( t_crossover ), 0, A_GIMME, 0 );
// declares leftmost inlet as a signal inlet
CLASS_MAINSIGNALIN( crossover_class, t_crossover, inlet_1 );
// installs crossover_dsp so that it will be called when dsp is turned on
class_addmethod( crossover_class, ( t_method )crossover_dsp, gensym( "dsp" ), 0 );
// add float handler
class_addfloat( crossover_class, crossover_float );
/*
// crossover arg class
//--------------------------------------------------------------------------
// creates an instance of this object and describes it to pd
crossover_arg_class = class_new( gensym( "crossover~" ), 0, 0, sizeof( t_crossover ), 0, 0 );
// declares leftmost inlet as a signal inlet
CLASS_MAINSIGNALIN( crossover_class, t_crossover, inlet_1 );
// installs crossover_dsp so that it will be called when dsp is turned on
class_addmethod( crossover_arg_class, ( t_method )crossover_dsp, gensym( "dsp" ), 0 );
*/
// announce this object in the pd console
Announce( "crossover~: splits signal at crossover frequency - v1.0" );
}
//------------------------------------------------------------------------------
// EOF
//------------------------------------------------------------------------------